/* Copyright (c) 2009, Enric Rodriguez (enrodri86@gmail.com)
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 	- Redistributions of source code must retain the above copyright
 * 	notice,	this list of conditions and the following disclaimer.
 * 	- Redistributions in binary form must reproduce the above copyright
 * 	notice, this list of conditions and the following disclaimer in the
 * 	documentation and/or other materials provided with the distribution.
 * 	- Neither the name of the <ORGANIZATION> nor the names of its
 * 	contributors may be used to endorse or promote products derived from
 * 	this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package es.enrodri86.mmo.auth.server;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Hashtable;
import java.util.Map;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import es.enrodri86.mmo.auth.shared.AuthException;
import es.enrodri86.mmo.auth.shared.Game;
import es.enrodri86.mmo.auth.shared.GameServer;
import es.enrodri86.mmo.auth.shared.HttpHeaders;

public class AuthServlet extends HttpServlet {

	private static final long serialVersionUID = 3762116358690938317L;

	private AuthServer as;
	private Thread ast;

	@Override
	public void init(ServletConfig sc) throws ServletException {
		String ins = sc.getInitParameter("AuthServer");
		try {
			Class c = Class.forName(ins);
			as = (AuthServer) c.newInstance();
			ast = new Thread(as);
			ast.start();
		} catch (InstantiationException ex) {
			throw new ServletException(ex);
		} catch (IllegalAccessException ex) {
			throw new ServletException(ex);
		} catch (ClassNotFoundException ex) {
			throw new ServletException(ex);
		}
	}

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		String op = req.getHeader(HttpHeaders.OP_REQUEST);
		if(op == null){
			//TODO what to do then? set location header to somwhere else?
			System.out.println("op = null");
			return;
		}

		if(op.equalsIgnoreCase(HttpHeaders.OP_CONNECT_REQUEST)){
			String session = as.getSession();
			try {
				as.connect(session, req.getRemoteHost());
				res.addHeader(HttpHeaders.SESSION_HEADER, session);
				if(as.isCaptchaRequired(session)){
					res.addHeader(HttpHeaders.CAPTCHA_REQUIRED_HEADER, "True");
					res.getOutputStream().print(as.getCaptcha(session).toXML());
				}

			} catch (AuthException e) {
				res.addHeader(HttpHeaders.EXCEPTION_CODE_HEADER, e.getCode()+"");
				res.addHeader(HttpHeaders.EXCEPTION_DESC_HEADER, e.getDescription());
			}
			return;
		}else if(op.equalsIgnoreCase(HttpHeaders.OP_LOGIN_REQUEST)){
			String session = req.getHeader(HttpHeaders.SESSION_HEADER);
			String user = req.getHeader(HttpHeaders.USER_REQUEST);
			String pass = req.getHeader(HttpHeaders.PASS_REQUEST);
			String captcha = req.getHeader(HttpHeaders.CAPTCHA_REQUEST);
			try {
				as.login(session,user,pass,captcha);
				res.addHeader(HttpHeaders.LOGIN_OK_HEADER, HttpHeaders.LOGIN_OK_VALUE);


				//ByteArrayOutputStream baos = new ByteArrayOutputStream();

				//PrintWriter pw = new PrintWriter(baos);

				PrintWriter pw = res.getWriter();

				pw.println("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");
				pw.println("<gamelist>");
				Map<String, Game> games = as.getGameList(session);
				Hashtable<String,GameServer> gsl = new Hashtable<String, GameServer>();
				for(String id : games.keySet()){
					Game g = games.get(id);
					pw.print("\t<game id=\""); pw.print(id); pw.println("\">");
					pw.print("\t\t<name><![CDATA["); pw.print(g.getName()); pw.println("]]></name>");
					pw.print("\t\t<desc><![CDATA["); pw.print(g.getDescription()); pw.println("]]></desc>");
					for(String gs : g.getServerIDsList()){
						pw.print("\t\t<serverid>"); pw.print(gs); pw.println("</serverid>");
						try{
							gsl.put(gs, as.getGameServerList().get(gs));
						}catch(NullPointerException e){
							//TODO send a message to the admin telling there is a problem with the configuration
						}
					}
					pw.println("\t</game>");
				}

				for(String id : gsl.keySet()){
					GameServer gs = gsl.get(id);
					pw.print("\t<server id=\""); pw.print(id); pw.println("\">");
					pw.print("\t\t<name><![CDATA["); pw.print(gs.getName()); pw.println("]]></name>");
					pw.print("\t\t<desc><![CDATA["); pw.print(gs.getDescription()); pw.println("]]></desc>");
					pw.print("\t\t<status>"); pw.print(gs.getStatus()); pw.println("</status>");
					pw.print("\t\t<host>"); pw.print(gs.getHost()); pw.println("</host>");
					pw.print("\t\t<port>"); pw.print(gs.getPort()); pw.println("</port>");
					pw.print("\t\t<url>"); pw.print(gs.getUrl()); pw.println("</url>");

					pw.println("\t</server>");
				}
				pw.println("</gamelist>");

				pw.flush();
				//System.out.write(baos.toByteArray());
				//res.getOutputStream().write(baos.toByteArray());

			} catch (AuthException e) {
				res.addHeader(HttpHeaders.EXCEPTION_CODE_HEADER, e.getCode()+"");
				res.addHeader(HttpHeaders.EXCEPTION_DESC_HEADER, e.getDescription());
			}
			return;
		}else if(op.equalsIgnoreCase(HttpHeaders.OP_CHOOSE_REQUEST)){
			String session = req.getHeader(HttpHeaders.SESSION_HEADER);
			String gid = req.getHeader(HttpHeaders.GAME_REQUEST);
			String gsid = req.getHeader(HttpHeaders.SERVER_REQUEST);
			if(gid != null && gsid != null && !gid.equals("") && !gsid.equals("")){
				Game g = as.getGameList(session).get(gid);
				if(g != null){
					if(g.getServerIDsList().contains(gid)){
						try {
							as.chooseGame(session, gid);
							as.chooseGameServer(session, gsid);
							res.addHeader(HttpHeaders.SESSION_HEADER, session);
						} catch (AuthException e) {
							res.addHeader(HttpHeaders.EXCEPTION_CODE_HEADER, e.getCode()+"");
							res.addHeader(HttpHeaders.EXCEPTION_DESC_HEADER, e.getDescription());
						}
					}else{
						res.addHeader(HttpHeaders.EXCEPTION_CODE_HEADER, "0");
						res.addHeader(HttpHeaders.EXCEPTION_DESC_HEADER,"Invalid game Server ID.");
					}
				}else{
					res.addHeader(HttpHeaders.EXCEPTION_CODE_HEADER, "0");
					res.addHeader(HttpHeaders.EXCEPTION_DESC_HEADER,"Invalid game ID.");
				}
			}else{
				res.addHeader(HttpHeaders.EXCEPTION_CODE_HEADER, "0");
				res.addHeader(HttpHeaders.EXCEPTION_DESC_HEADER,"Game server ID and game ID must be specified.");
			}
		}
	}
}